const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const chalk = require('chalk');
const logger = require("./utils/utils.logger");
const mount = require('mount-routes');
const app = express();
const cors = require('cors');
const dotenv = require('dotenv');
const session = require('express-session');
const WebSocket = require('ws');
const db = require("./models");
const ChatMessage = db.chatMessage; // 引入 ChatMessage 模型
const http = require('http');
const socketIo = require('socket.io');

dotenv.config();
app.use(session({
    secret: "WickYo",
    name: "session",
    resave: false,
    rolling: false,
    cookie: {
        maxAge: 300000
    }
}));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

db.sequelize.sync();

// 设置跨域
app.use(cors());
app.all('/api/*', function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, token');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, Authorization');
    res.header('Content-Type', 'application/json;charset=UTF-8');
    res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With');
    res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
    if (req.method == 'OPTIONS') res.send(200);
    else next();
});

const expressSwagger = require('express-swagger-generator')(app);
const options = require('./utils/swagger');
expressSwagger(options);

const UnifiedResponse = require('./utils/utils.resextra');
app.use(UnifiedResponse);

const admin_passport = require('./utils/utils.permission');
app.use('/api/private/*', admin_passport.tokenAuth);
app.use('/api/private/*', admin_passport.permissionAuth);

app.use(function (err, req, res, next) {
    if (err.name === 'UnauthorizedError') {
        logger.error(`${req.method} ${req.baseUrl + req.path} *** 响应：${JSON.stringify({
            data: null,
            code: err.status || 401,
            message: err.message || 'token错误'
        })}`);
        res.status(401).send({ data: null, code: err.status || 401, message: err.message || 'token错误' });
    }
});

// WebSocket 服务器部分
const server = http.createServer(app);

// 使用http服务器监听端口
server.listen(process.env.DEV_PORT, () => {
    console.log(chalk.bold.green(`项目启动成功: ${process.env.DEV_URL}:${process.env.DEV_PORT}`));
    console.log(chalk.bold.green(`接口文档地址: ${process.env.DEV_URL}:${process.env.DEV_PORT}/swagger`));
});

// 创建 WebSocket 服务器并与 Express 服务器共享端口
const wss = new WebSocket.Server({ server });

// 用于存储用户与 WebSocket 连接的映射关系
let userConnections = {};

// 处理 WebSocket 连接
wss.on('connection', (ws) => {
    console.log('新用户连接');

    // 在连接建立时为每个用户分配唯一标识符，并存储其连接
    ws.on('message', async (message) => {
        const parsedMessage = JSON.parse(message);

        if (parsedMessage.type === 'register') {
            const { userId } = parsedMessage;  // 用户注册消息
            userConnections[userId] = ws;  // 将 WebSocket 实例与 userId 关联
            console.log(`用户 ${userId} 已连接`);
        } else if (parsedMessage.type === 'chat') {
            const { toUserId, fromUserId, messageText, chatType,senderHead } = parsedMessage;

            // 构建数据库消息对象
            const newMessage = {
                sender: fromUserId,
                receiver: chatType === 'private' ? toUserId : 'group',  // 群聊时，receiver 可以是 'group'
                type: chatType,
                senderHead: senderHead,  // 用户头像
                message: messageText,
            };

            // 保存消息到数据库
            await ChatMessage.create(newMessage);

            if (chatType === 'private') {
                // 私聊: 发送消息给指定用户
                const targetSocket = userConnections[toUserId];
                if (targetSocket && targetSocket.readyState === WebSocket.OPEN) {
                    targetSocket.send(JSON.stringify({
                        type: 'chat',
                        message: messageText,
                        sender: fromUserId,
                    }));
                    console.log(`私聊消息发送给用户 ${toUserId}`);
                } else {
                    console.log(`目标用户 ${toUserId} 不在线`);
                }
            } else if (chatType === 'group') {
                // 群聊: 广播消息给所有连接的用户（假设我们已经知道群组的成员列表）
                for (let userId in userConnections) {
                    const userSocket = userConnections[userId];
                    if (userSocket && userSocket.readyState === WebSocket.OPEN) {
                        userSocket.send(JSON.stringify({
                            type: 'chat',
                            message: messageText,
                            sender: fromUserId,
                        }));
                    }
                }
                console.log(`群聊消息发送给所有用户`);
            }
        }
    });

    // 用户断开连接时的处理
    ws.on('close', () => {
        // 找到并删除断开连接的用户
        for (let userId in userConnections) {
            if (userConnections[userId] === ws) {
                delete userConnections[userId];
                console.log(`用户 ${userId} 断开连接`);
                break;
            }
        }
    });
});

// 初始化Socket.io
const io = socketIo(server, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"]
  }
});

// 用户连接映射
const userSocketMap = new Map();

// WebSocket连接处理
io.on('connection', (socket) => {
  console.log('A user connected');
  
  // 用户加入
  socket.on('join', (data) => {
    if (data.username) {
      userSocketMap.set(data.username, socket.id);
      console.log(`User ${data.username} joined with socket ID: ${socket.id}`);
    }
  });
  
  // 聊天消息
  socket.on('chat message', (msg) => {
    console.log('Message received:', msg);
    
    // 广播消息给所有连接的客户端
    io.emit('chat message', msg);
    
    // 如果要定向发送给特定用户，可以使用以下代码
    // const targetSocketId = userSocketMap.get(msg.receive);
    // if (targetSocketId) {
    //   io.to(targetSocketId).emit('chat message', msg);
    // }
  });
  
  // 断开连接
  socket.on('disconnect', () => {
    console.log('User disconnected');
    // 从映射中移除用户
    for (const [username, socketId] of userSocketMap.entries()) {
      if (socketId === socket.id) {
        userSocketMap.delete(username);
        console.log(`User ${username} disconnected`);
        break;
      }
    }
  });
});

// 路由加载
mount(app, path.join(process.cwd(), '/routes'), true);

// 处理无响应路径
app.use(function (req, res, next) {
    res.status(404).sendResult({ data: null, code: 404, message: 'Not Found' });
});

module.exports = app;
